<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <video id="video" autoplay muted playsinline></video>
</body>
<script type="module">
import BarcodeDetectorPolyfill from "https://cdn.skypack.dev/barcode-detector@1.0.3";

const adaptOldFormat = detectedCodes => {
  if (detectedCodes.length > 0) {
    const [ firstCode ] = detectedCodes;

    const [
      topLeftCorner,
      topRightCorner,
      bottomRightCorner,
      bottomLeftCorner
    ] = firstCode.cornerPoints

    return {
      content: firstCode.rawValue,
      location: {
        topLeftCorner,
        topRightCorner,
        bottomRightCorner,
        bottomLeftCorner,

        // not supported by native API:
        topLeftFinderPattern: {},
        topRightFinderPattern: {},
        bottomLeftFinderPattern: {}
      },
      imageData: null
    }
  } else {
    return {
      content: null,
      location: null,
      imageData: null
    }
  }
}

export const keepScanning = (videoElement, options) => {
  const barcodeDetector = new BarcodeDetectorPolyfill({ formats: ["qr_code"] });

  const { detectHandler, locateHandler, minDelay } = options;

  const processFrame = state => async timeNow => {
    if (videoElement.readyState > 1) {
      console.log("scan")
      const { lastScanned, contentBefore, locationBefore } = state

      if (timeNow - lastScanned >= minDelay) {
        const detectedCodes = await barcodeDetector.detect(videoElement);
        const { content, location, imageData } = adaptOldFormat(detectedCodes)

        if (content !== null && content !== contentBefore) {
          detectHandler({ content, location, imageData });
        }

        if (location !== null || locationBefore !== null) {
          locateHandler(detectedCodes);
        }

        window.requestAnimationFrame(processFrame({
          lastScanned: timeNow,
          contentBefore: content ?? contentBefore,
          locationBefore: location
        }))
      } else {
        window.requestAnimationFrame(processFrame(state))
      }
    }
  };

  processFrame({
    contentBefore: null,
    locationBefore: null,
    lastScanned: performance.now()
  })();
};

(async () => {
  const videoEl = document.querySelector('#video')

  const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false })

  videoEl.srcObject = stream

  videoEl.addEventListener("loadeddata", () => {
      keepScanning(videoEl, { minDelay: 40, detectHandler: console.log, locateHandler: console.log })
  })

})()
</script>
</html>
